package com.zaimokuza.cn.config.handler;

import com.alibaba.fastjson.JSON;
import com.zaimokuza.cn.entity.constants.ResponseConstant;
import com.zaimokuza.cn.entity.exception.CustomizeException;
import com.zaimokuza.cn.entity.response.ResponseEntity;
import com.zaimokuza.cn.entity.response.ResponseFormat;
import com.zaimokuza.cn.util.grace.GraceResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;


/**
 * 返回值封装及异常处理
 *
 * @author zaimokuza
 */
@Slf4j
@RestControllerAdvice
public class ResponseHandler implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // 查看请求中是否包含了标记注解，如果没有包含直接返回，不需要进行包装
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert sra != null;
        HttpServletRequest request = sra.getRequest();
        ResponseFormat responseMark = (ResponseFormat) request.getAttribute(ResponseConstant.RESPONSE_FORMAT_MARK);
        return responseMark != null;
    }

    @Override
    public Object beforeBodyWrite(Object result, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> clazz, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        // 特殊处理
        if (result instanceof ResponseEntity) {
            // 如果是全局异常处理器的返回值,直接进行返回
            return result;
        } else if (result instanceof String) {
            // 如果是String格式，单独包装并进行JSON转换，否则会报错
            return JSON.toJSONString(GraceResponse.success(result));
        }
        // 对返回体进行包装
        return GraceResponse.success(result);
    }

    /**
     * 全局异常处理
     */
    @ExceptionHandler(value = CustomizeException.class)
    public ResponseEntity customizeExceptionHandler(CustomizeException exception) {
        // 打印异常信息
        log.error(exception.getMessage());
        // 封装并返回
        return GraceResponse.error(exception.getCustomizeExceptionEnum(), exception.getResultMsg());
    }

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResponseEntity methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException exception) {
        // 获取校验异常结果集合
        BindingResult bindingResult = exception.getBindingResult();
        List<FieldError> fieldErrors = bindingResult.getFieldErrors();
        // 实例化返回给前台的Map集合
        HashMap<String, String> errorMap = new HashMap<>(fieldErrors.size());
        // 整理出校验异常的属性和提示信息
        for (FieldError fieldError : fieldErrors) {
            errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
        }
        // 封装返回对象返回
        return GraceResponse.errorMap(errorMap);
    }

    @ExceptionHandler(value = Exception.class)
    public ResponseEntity exceptionHandler(Exception exception) {
        // 打印异常信息
        log.error(exception.getMessage(), exception);
        // 封装并返回
        return GraceResponse.error();
    }

}
